home *** CD-ROM | disk | FTP | other *** search
/ Aminet 32 / Aminet 32 (1999)(Schatztruhe)[!][Aug 1999].iso / Aminet / dev / lang / Python151_Src.lha / Python1.5_Source / Modules / selectmodule.c < prev    next >
C/C++ Source or Header  |  1998-12-25  |  11KB  |  460 lines

  1. /***********************************************************
  2. Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
  3. The Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its
  8. documentation for any purpose and without fee is hereby granted,
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI or Corporation for National Research Initiatives or
  13. CNRI not be used in advertising or publicity pertaining to
  14. distribution of the software without specific, written prior
  15. permission.
  16.  
  17. While CWI is the initial source for this software, a modified version
  18. is made available by the Corporation for National Research Initiatives
  19. (CNRI) at the Internet address ftp://ftp.python.org.
  20.  
  21. STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
  22. REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  23. MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
  24. CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  25. DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  26. PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  27. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  28. PERFORMANCE OF THIS SOFTWARE.
  29.  
  30. ******************************************************************/
  31.  
  32. /* select - Module containing unix select(2) call.
  33.    Under Unix, the file descriptors are small integers.
  34.    Under Win32, select only exists for sockets, and sockets may
  35.    have any value except INVALID_SOCKET.
  36. */
  37.  
  38. #include "Python.h"
  39.  
  40. #ifdef HAVE_UNISTD_H
  41. #include <unistd.h>
  42. #endif
  43.  
  44. #ifdef __sgi
  45. /* This is missing from unistd.h */
  46. extern void bzero();
  47. #endif
  48.  
  49. #include <sys/types.h>
  50.  
  51. #if defined(PYOS_OS2)
  52. #include <sys/time.h>
  53. #include <utils.h>
  54. #endif
  55.  
  56. #ifdef MS_WINDOWS
  57. #include <winsock.h>
  58. #else
  59. #include "myselect.h" /* Also includes mytime.h */
  60. #define SOCKET int
  61. #endif
  62.  
  63. static PyObject *SelectError;
  64.  
  65. /* list of Python objects and their file descriptor */
  66. typedef struct {
  67.     PyObject *obj;                 /* owned reference */
  68.     SOCKET fd;
  69.     int sentinel;                 /* -1 == sentinel */
  70. } pylist;
  71.  
  72. #include "protos/selectmodule_protos.h"
  73.  
  74. static void
  75. reap_obj(fd2obj)
  76.     pylist fd2obj[FD_SETSIZE + 3];
  77. {
  78.     int i;
  79.     for (i = 0; i < FD_SETSIZE + 3 && fd2obj[i].sentinel >= 0; i++) {
  80.         Py_XDECREF(fd2obj[i].obj);
  81.         fd2obj[i].obj = NULL;
  82.     }
  83.     fd2obj[0].sentinel = -1;
  84. }
  85.  
  86.  
  87. /* returns -1 and sets the Python exception if an error occurred, otherwise
  88.    returns a number >= 0
  89. */
  90. static int
  91. list2set(list, set, fd2obj)
  92.     PyObject *list;
  93.     fd_set *set;
  94.     pylist fd2obj[FD_SETSIZE + 3];
  95. {
  96.     int i;
  97.     int max = -1;
  98.     int index = 0;
  99.     int len = PyList_Size(list);
  100.     PyObject* o = NULL;
  101.  
  102.     fd2obj[0].obj = (PyObject*)0;         /* set list to zero size */
  103.     FD_ZERO(set);
  104.  
  105.     for (i = 0; i < len; i++)  {
  106.         PyObject *meth;
  107.         SOCKET v;
  108.  
  109.         /* any intervening fileno() calls could decr this refcnt */
  110.         if (!(o = PyList_GetItem(list, i)))
  111.                     return -1;
  112.  
  113.         Py_INCREF(o);
  114.  
  115.         if (PyInt_Check(o)) {
  116.             v = PyInt_AsLong(o);
  117.         }
  118.         else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL)
  119.         {
  120.             PyObject *fno = PyEval_CallObject(meth, NULL);
  121.             Py_DECREF(meth);
  122.             if (fno == NULL)
  123.                 goto finally;
  124.  
  125.                         if (!PyInt_Check(fno)) {
  126.                 PyErr_SetString(PyExc_TypeError,
  127.                                        "fileno method returned a non-integer");
  128.                 Py_DECREF(fno);
  129.                 goto finally;
  130.                         }
  131.                         v = PyInt_AsLong(fno);
  132.             Py_DECREF(fno);
  133.         }
  134.         else {
  135.             PyErr_SetString(PyExc_TypeError,
  136.             "argument must be an int, or have a fileno() method.");
  137.             goto finally;
  138.         }
  139. #ifdef _MSC_VER
  140.         max = 0;             /* not used for Win32 */
  141. #else  /* !_MSC_VER */
  142.         if (v < 0 || v >= FD_SETSIZE) {
  143.             PyErr_SetString(PyExc_ValueError,
  144.                     "filedescriptor out of range in select()");
  145.             goto finally;
  146.         }
  147.         if (v > max)
  148.             max = v;
  149. #endif /* _MSC_VER */
  150.         FD_SET(v, set);
  151.  
  152.         /* add object and its file descriptor to the list */
  153.         if (index >= FD_SETSIZE) {
  154.             PyErr_SetString(PyExc_ValueError,
  155.                       "too many file descriptors in select()");
  156.             goto finally;
  157.         }
  158.         fd2obj[index].obj = o;
  159.         fd2obj[index].fd = v;
  160.         fd2obj[index].sentinel = 0;
  161.         fd2obj[++index].sentinel = -1;
  162.     }
  163.     return max+1;
  164.  
  165.   finally:
  166.     Py_XDECREF(o);
  167.     return -1;
  168. }
  169.  
  170. /* returns NULL and sets the Python exception if an error occurred */
  171. static PyObject *
  172. set2list(set, fd2obj)
  173.     fd_set *set;
  174.     pylist fd2obj[FD_SETSIZE + 3];
  175. {
  176.     int i, j, count=0;
  177.     PyObject *list, *o;
  178.     SOCKET fd;
  179.  
  180.     for (j = 0; fd2obj[j].sentinel >= 0; j++) {
  181.         if (FD_ISSET(fd2obj[j].fd, set))
  182.             count++;
  183.     }
  184.     list = PyList_New(count);
  185.     if (!list)
  186.         return NULL;
  187.  
  188.     i = 0;
  189.     for (j = 0; fd2obj[j].sentinel >= 0; j++) {
  190.         fd = fd2obj[j].fd;
  191.         if (FD_ISSET(fd, set)) {
  192. #ifndef _MSC_VER
  193.             if (fd > FD_SETSIZE) {
  194.                 PyErr_SetString(PyExc_SystemError,
  195.                "filedescriptor out of range returned in select()");
  196.                 goto finally;
  197.             }
  198. #endif
  199.             o = fd2obj[j].obj;
  200.             fd2obj[j].obj = NULL;
  201.             /* transfer ownership */
  202.             if (PyList_SetItem(list, i, o) < 0)
  203.                 goto finally;
  204.  
  205.             i++;
  206.         }
  207.     }
  208.     return list;
  209.   finally:
  210.     Py_DECREF(list);
  211.     return NULL;
  212. }
  213.  
  214. #if defined(AMITCP) || defined(INET225)
  215. /*** AMIGA VERSION OF SELECT: WaitSelect()/selectwait() support ***/
  216. /*** (additional 5th parameter: signal waitmask)    ***/
  217.  
  218. static PyObject *
  219. select_select(PyObject *self, PyObject *args)
  220. {
  221.     pylist rfd2obj[FD_SETSIZE + 3];
  222.     pylist wfd2obj[FD_SETSIZE + 3];
  223.     pylist efd2obj[FD_SETSIZE + 3];
  224.     PyObject *ifdlist, *ofdlist, *efdlist;
  225.     PyObject *ret = NULL;
  226.     PyObject *tout = Py_None;
  227.     fd_set ifdset, ofdset, efdset;
  228.     double timeout;
  229.     struct timeval tv, *tvp;
  230.     int seconds;
  231.     int imax, omax, emax, max;
  232.     int n;
  233.     ULONG waitmask=0;
  234.     BOOL do_waitmask = FALSE;
  235.  
  236.     /* convert arguments */
  237.     if (!PyArg_ParseTuple(args, "OOO|Oi",
  238.                   &ifdlist, &ofdlist, &efdlist, &tout, &waitmask))
  239.         return NULL;
  240.  
  241.     if (tout == Py_None)
  242.         tvp = (struct timeval *)0;
  243.     else if (!PyArg_Parse(tout, "d", &timeout)) {
  244.         PyErr_SetString(PyExc_TypeError,
  245.                 "timeout must be a float or None");
  246.         return NULL;
  247.     }
  248.     else {
  249.         seconds = (int)timeout;
  250.         timeout = timeout - (double)seconds;
  251.         tv.tv_sec = seconds;
  252.         tv.tv_usec = (int)(timeout*1000000.0);
  253.         tvp = &tv;
  254.     }
  255.  
  256.     if(waitmask) do_waitmask=TRUE;
  257.  
  258.     /* sanity check first three arguments */
  259.     if (!PyList_Check(ifdlist) ||
  260.         !PyList_Check(ofdlist) ||
  261.         !PyList_Check(efdlist))
  262.     {
  263.         PyErr_SetString(PyExc_TypeError,
  264.                 "arguments 1-3 must be lists");
  265.         return NULL;
  266.     }
  267.  
  268.     /* Convert lists to fd_sets, and get maximum fd number
  269.      * propagates the Python exception set in list2set()
  270.      */
  271.     rfd2obj[0].sentinel = -1;
  272.     wfd2obj[0].sentinel = -1;
  273.     efd2obj[0].sentinel = -1;
  274.     if ((imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0) 
  275.         goto finally;
  276.     if ((omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0) 
  277.         goto finally;
  278.     if ((emax=list2set(efdlist, &efdset, efd2obj)) < 0) 
  279.         goto finally;
  280.     max = imax;
  281.     if (omax > max) max = omax;
  282.     if (emax > max) max = emax;
  283.  
  284.     Py_BEGIN_ALLOW_THREADS
  285. #ifdef AMITCP
  286.     n = WaitSelect(max, &ifdset, &ofdset, &efdset, tvp, &waitmask);
  287. #else /* INET225 */
  288.     n = selectwait(max, &ifdset, &ofdset, &efdset, tvp, &waitmask);
  289. #endif    
  290.     Py_END_ALLOW_THREADS
  291.  
  292.     if (n < 0) {
  293.         PyErr_SetFromErrno(SelectError);
  294.     }
  295.     else if (n == 0) {
  296.                 /* optimization */
  297.         ifdlist = PyList_New(0);
  298.         if (ifdlist) {
  299.             if(do_waitmask) ret=Py_BuildValue("OOOi", ifdlist, ifdlist, ifdlist, waitmask);
  300.             else ret=Py_BuildValue("OOO", ifdlist, ifdlist, ifdlist);
  301.             Py_DECREF(ifdlist);
  302.         }
  303.     }
  304.     else {
  305.         /* any of these three calls can raise an exception.  it's more
  306.            convenient to test for this after all three calls... but
  307.            is that acceptable?
  308.         */
  309.         ifdlist = set2list(&ifdset, rfd2obj);
  310.         ofdlist = set2list(&ofdset, wfd2obj);
  311.         efdlist = set2list(&efdset, efd2obj);
  312.         if (PyErr_Occurred())
  313.             ret = NULL;
  314.         else
  315.         {
  316.             if(do_waitmask) ret=Py_BuildValue("OOOi", ifdlist, ofdlist, efdlist, waitmask);
  317.             else ret=Py_BuildValue("OOO", ifdlist, ofdlist, efdlist);
  318.         }
  319.  
  320.         Py_DECREF(ifdlist);
  321.         Py_DECREF(ofdlist);
  322.         Py_DECREF(efdlist);
  323.     }
  324.     
  325.   finally:
  326.     reap_obj(rfd2obj);
  327.     reap_obj(wfd2obj);
  328.     reap_obj(efd2obj);
  329.     return ret;
  330. }
  331.  
  332. #else /* ! AMITCP || INET225 */
  333. /** This is the original select function without the 5th argument **/
  334.  
  335. static PyObject *
  336. select_select(self, args)
  337.     PyObject *self;
  338.     PyObject *args;
  339. {
  340.     pylist rfd2obj[FD_SETSIZE + 3];
  341.     pylist wfd2obj[FD_SETSIZE + 3];
  342.     pylist efd2obj[FD_SETSIZE + 3];
  343.     PyObject *ifdlist, *ofdlist, *efdlist;
  344.     PyObject *ret = NULL;
  345.     PyObject *tout = Py_None;
  346.     fd_set ifdset, ofdset, efdset;
  347.     double timeout;
  348.     struct timeval tv, *tvp;
  349.     int seconds;
  350.     int imax, omax, emax, max;
  351.     int n;
  352.  
  353.     /* convert arguments */
  354.     if (!PyArg_ParseTuple(args, "OOO|O",
  355.                   &ifdlist, &ofdlist, &efdlist, &tout))
  356.         return NULL;
  357.  
  358.     if (tout == Py_None)
  359.         tvp = (struct timeval *)0;
  360.     else if (!PyArg_Parse(tout, "d", &timeout)) {
  361.         PyErr_SetString(PyExc_TypeError,
  362.                 "timeout must be a float or None");
  363.         return NULL;
  364.     }
  365.     else {
  366.         seconds = (int)timeout;
  367.         timeout = timeout - (double)seconds;
  368.         tv.tv_sec = seconds;
  369.         tv.tv_usec = (int)(timeout*1000000.0);
  370.         tvp = &tv;
  371.     }
  372.  
  373.     /* sanity check first three arguments */
  374.     if (!PyList_Check(ifdlist) ||
  375.         !PyList_Check(ofdlist) ||
  376.         !PyList_Check(efdlist))
  377.     {
  378.         PyErr_SetString(PyExc_TypeError,
  379.                 "arguments 1-3 must be lists");
  380.         return NULL;
  381.     }
  382.  
  383.     /* Convert lists to fd_sets, and get maximum fd number
  384.      * propagates the Python exception set in list2set()
  385.      */
  386.     rfd2obj[0].sentinel = -1;
  387.     wfd2obj[0].sentinel = -1;
  388.     efd2obj[0].sentinel = -1;
  389.     if ((imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0) 
  390.         goto finally;
  391.     if ((omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0) 
  392.         goto finally;
  393.     if ((emax=list2set(efdlist, &efdset, efd2obj)) < 0) 
  394.         goto finally;
  395.     max = imax;
  396.     if (omax > max) max = omax;
  397.     if (emax > max) max = emax;
  398.  
  399.     Py_BEGIN_ALLOW_THREADS
  400.     n = select(max, &ifdset, &ofdset, &efdset, tvp);
  401.     Py_END_ALLOW_THREADS
  402.  
  403.     if (n < 0) {
  404.         PyErr_SetFromErrno(SelectError);
  405.     }
  406.     else if (n == 0) {
  407.                 /* optimization */
  408.         ifdlist = PyList_New(0);
  409.         if (ifdlist) {
  410.             ret = Py_BuildValue("OOO", ifdlist, ifdlist, ifdlist);
  411.             Py_DECREF(ifdlist);
  412.         }
  413.     }
  414.     else {
  415.         /* any of these three calls can raise an exception.  it's more
  416.            convenient to test for this after all three calls... but
  417.            is that acceptable?
  418.         */
  419.         ifdlist = set2list(&ifdset, rfd2obj);
  420.         ofdlist = set2list(&ofdset, wfd2obj);
  421.         efdlist = set2list(&efdset, efd2obj);
  422.         if (PyErr_Occurred())
  423.             ret = NULL;
  424.         else
  425.             ret = Py_BuildValue("OOO", ifdlist, ofdlist, efdlist);
  426.  
  427.         Py_DECREF(ifdlist);
  428.         Py_DECREF(ofdlist);
  429.         Py_DECREF(efdlist);
  430.     }
  431.     
  432.   finally:
  433.     reap_obj(rfd2obj);
  434.     reap_obj(wfd2obj);
  435.     reap_obj(efd2obj);
  436.     return ret;
  437. }
  438.  
  439. #endif /* !AMITCP */
  440.  
  441.  
  442. static PyMethodDef select_methods[] = {
  443.     {"select",    select_select, 1},
  444.     {0,      0},                 /* sentinel */
  445. };
  446.  
  447.  
  448. void
  449. initselect()
  450. {
  451.     PyObject *m, *d;
  452. #if defined(AMITCP) || defined(INET225)
  453.     if(!checksocketlib()) return;
  454. #endif
  455.     m = Py_InitModule("select", select_methods);
  456.     d = PyModule_GetDict(m);
  457.     SelectError = PyErr_NewException("select.error", NULL, NULL);
  458.     PyDict_SetItemString(d, "error", SelectError);
  459. }
  460.